﻿/**
 * ...
 * @author aboutwhat
 */

package format.hxml;

import haxe.io.Output;
import format.hxml.Data.Data;
import format.hxml.Data.Library;
import format.hxml.Data.Option;
import format.hxml.Data.Resource;
import format.hxml.Data.SwfHeader;
import format.hxml.Data.Remap;


private typedef CS = format.hxml.Constants;

class Writer 
{
    static inline var PREFIX_1 = "-";
    static inline var PREFIX_2 = "--";
    
    var output:Output;
    
    public function new (o : Output) 
    { 
        output = o;
    }
    
    public function write (h:Data, ?lineSeparator:String = "\n")
    {
        output.bigEndian = true;
        
        for (o in h) output.writeString(enumToString(o) + lineSeparator);    
    }
    
    function formatOption (prefix:String, opt : String, ?value:String) : String 
    {
        var res = prefix + opt;
        if (value != null) res += " " + value;
        return res;
    }
    
    
    function enumToString (opt : Option) 
    {
        
        return switch (opt) 
        {
            // p1 -option
            case cp(v) :          formatOption(PREFIX_1, CS.cp, v);
            case js(v) :          formatOption(PREFIX_1, CS.js, v);
            case swf(v) :         formatOption(PREFIX_1, CS.swf, v);
            case swf9(v) :        formatOption(PREFIX_1, CS.swf9, v);
            case as3(v) :         formatOption(PREFIX_1, CS.as3, v);
            case neko(v) :        formatOption(PREFIX_1, CS.neko, v);
            case php(v) :         formatOption(PREFIX_1, CS.php, v);
            case cpp(v) :         formatOption(PREFIX_1, CS.cpp, v);
            case xml(v) :         formatOption(PREFIX_1, CS.xml, v);
            case main(v) :        formatOption(PREFIX_1, CS.main, v);
            case lib(v) :         formatOption(PREFIX_1, CS.lib, libraryToStr(v));
            case D(v) :           formatOption(PREFIX_1, CS.D, v);
            case v :              formatOption(PREFIX_1, CS.v);
            case debug :          formatOption(PREFIX_1, CS.debug);
            case swfVersion(v) :  formatOption(PREFIX_1, CS.swfVersion, Std.string(v));
            case swfHeader(v) :   formatOption(PREFIX_1, CS.swfHeader, swfHeaderToStr(v));
            case swfLib(v) :      formatOption(PREFIX_1, CS.swfLib, v);
            case x(v) :           formatOption(PREFIX_1, CS.x, v);
            case resource(v) :    formatOption(PREFIX_1, CS.resource, resourceToStr(v));
            case exclude(v) :     formatOption(PREFIX_1, CS.exclude, v);
            case prompt :         formatOption(PREFIX_1, CS.prompt);
            case cmd(v) :         formatOption(PREFIX_1, CS.cmd, v);
            // p2 --option
            case flashStrict :    formatOption(PREFIX_2, CS.flashStrict);
            case noTraces :       formatOption(PREFIX_2, CS.noTraces);
            case flashUseStage :  formatOption(PREFIX_2, CS.flashUseStage);
            case nekoSource :     formatOption(PREFIX_2, CS.nekoSource);
            case genHxHeaders :   formatOption(PREFIX_2, CS.genHxHeaders);
            case display :        formatOption(PREFIX_2, CS.display);
            case noOutput :       formatOption(PREFIX_2, CS.noOutput);
            case times :          formatOption(PREFIX_2, CS.times);
            case noInline :       formatOption(PREFIX_2, CS.noInline);
            case noOpt :          formatOption(PREFIX_2, CS.noOpt);
            case phpFront(v) :    formatOption(PREFIX_2, CS.phpFront, v);
            case jsNamespace(v) : formatOption(PREFIX_2, CS.jsNamespace, v);
            case remap(v) :       formatOption(PREFIX_2, CS.remap, remapToStr(v));
            case help :           formatOption(PREFIX_2, CS.help);
            case next :           formatOption(PREFIX_2, CS.next);
            
        }
    }
    
    function libraryToStr (lib :Library) : String
    {
        return lib.library + ((lib.version != null) ? (":" + lib.version) : "");    
    }
    
    function remapToStr (remap:Remap) : String
    {
        return remap.source + ":" + remap.target;
    }
    
    inline function toHexChar (a : Int) : String
    {
        return switch (a) {
            case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 : Std.parseInt(a);
            case 10 : "A"; 
            case 11 : "B";
            case 12 : "C";
            case 13 : "D";
            case 14 : "E";
            case 15 : "F";
        }
    }
    
    inline function toBase16 (a : Int, chars:Int) : String
    {
        var mask = 0xFF;
        var res = "";
        var offset = (8 - chars) * 4;
        for (i in 0...chars) {
            res += toHexChar((a >> (32 - offset * i )) & mask)
            
        }
        return res;
        
    }
    
    function swfHeaderToStr (header:SwfHeader) : String
    {
     
        
        return header.width + ":" + header.height + ":" + header.fps + ":" + toBase16(header.color);
    }
    
    function resourceToStr (res:Resource) : String
    {
        return res.file + "@" + res.name;
    }
    
    
    
}